package NWPackage;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

import Readers.InputsReader;

public class ProbabilitiesMatrix extends Matrix {
	//the probability matrix is ordered by the index
	
	//<Agent, Sum Probabilities>
	private Hashtable<String,Double> agentsTotalProbabilities;
	
	public ProbabilitiesMatrix() {
		super();
	}

	

	public ProbabilitiesMatrix(ProbabilityCell[] cells) {
		super(cells);
	}
	
	public ProbabilitiesMatrix(ProbabilityCell[] cells,Hashtable<String, Double> agentTotalProbabilities) {
		super(cells);
		this.agentsTotalProbabilities = agentTotalProbabilities;
	}


	public String[] getAgentsNames()
	{
		String[] array = this.agentsTotalProbabilities.keySet().toArray(new String[this.agentsTotalProbabilities.size()]);
		return array;
		//return (String[])(this.agentsTotalProbabilities.keySet().toArray());
	}

	public void initial(ProbabilityCell[] cells) {
		this.cells = cells;
		agentsTotalProbabilities = new Hashtable<String, Double>();
		InitSumOfProbabilities(null,agentsTotalProbabilities,1.0);
		
	}
	
	public double getAgentTotalProbability(String agentName)
	{
		return this.agentsTotalProbabilities.get(agentName);
	}
	public Cell getCell(int index)
	{
		if (index < cells.length)
			return (ProbabilityCell)cells[index];
		return null;
	}

	public ProbabilitiesMatrix normalize(PairPreferdCandidateCell preferredCell) {
		
		ProbabilitiesMatrix normalizeMatrix;
		List<ProbabilityCell> normalizedCells = new ArrayList<ProbabilityCell>();
				
		//create Hash to save all Sum of probability per Agent
		Hashtable<String,Double> normSumProbabilities = new Hashtable<String, Double>();
		InitSumOfProbabilities(preferredCell,normSumProbabilities,0);
		
		//build new probability matrix normalized with relevant cells by the preferred cell
		getRelevantCellsAndProbs(preferredCell,normalizedCells,normSumProbabilities);
		
		//calc the sum of the 
		//Normalize all the Probabilities according to the New Sum Probabilities of each Agent
		calcNormProbabilities(normalizedCells,normSumProbabilities);
		
		//return the new Normalized Probability Matrix
		ProbabilityCell[] newCells = (ProbabilityCell[])normalizedCells.toArray(new ProbabilityCell[0]);
		normalizeMatrix = new ProbabilitiesMatrix(newCells,normSumProbabilities);
		return normalizeMatrix;
	}
	
	
	
	
	private void calcNormProbabilities(List<ProbabilityCell> normalizedCells,
			Hashtable<String, Double> normSumProbabilities) {

		for (ProbabilityCell cell : normalizedCells) {
			try {
				cell.setProbability(cell.getProbability() / normSumProbabilities.get(cell.getAgentName()));
			} catch (Exception e) {
				System.out.println("error with probability: " +cell.getProbability()+"  for agent: " +cell.getAgentName() );
				try {
					cell.setProbability(1.0);
				} catch (Exception e1) {
					e1.printStackTrace();
				}
			}
		}
		
	}

	private void getRelevantCellsAndProbs(PairPreferdCandidateCell preferredCell,
				List<ProbabilityCell> relevantCells,
				Hashtable<String, Double> normSumProbabilities) {
		String[] agents = InputsReader.getAgents();
		
		for (String agent : agents) {
			//for each agent, get his probabilities - except for the agent in the query
			if (agent == preferredCell.getAgentName())
			{
				//get relevant probs only
				relevantCells.addAll(this.getAgentRelevantProbsWithSum(agent, preferredCell,normSumProbabilities));
				
			}
			else
			{
				//get regular probs
				relevantCells.addAll(this.getAgentProbs(agent));
				normSumProbabilities.put(agent, normSumProbabilities.get(agent));
			}
		}
	}
	

	private List<ProbabilityCell> getAgentRelevantProbsWithSum(String agent,PairPreferdCandidateCell preferredCell, Hashtable<String, Double> normSumProbabilities)
	{
		List<ProbabilityCell> agentProbs = this.getAgentProbs(agent);
		List<ProbabilityCell> relevant = new ArrayList<ProbabilityCell>();
		
		for (ProbabilityCell probabilityCell : agentProbs) {
			if (probabilityCell.isEqualsPreferredOrder(preferredCell) && probabilityCell.getProbability()>0)
			{
				relevant.add(new ProbabilityCell(probabilityCell));
			
				//update the sum of the Agent's probabilities
				double agentCurrentProb = normSumProbabilities.get(agent);
				normSumProbabilities.put(agent, agentCurrentProb+probabilityCell.getProbability());
			}
		}
		return relevant;
		
	}



	//part of the initial sum of probabilities of 1.0 per agent
	private void InitSumOfProbabilities(PairPreferdCandidateCell preferredCell, Hashtable<String, Double> agentProb,double prob) {
		//only for the new query's agent - initial the Sum probability
		String[] agents = InputsReader.getAgents();
		
		for (String agentName : agents) {
			if (preferredCell == null || agentName == preferredCell.getAgentName()){
				agentProb.put(agentName, prob);
			}
			else
			{
				agentProb.put(agentName, this.getAgentTotalProbability(agentName));
			}
		}
		return;
	}



	public ProbabilityCell getProbability(String agent, double randomProb) {
		double sum=0;
		//get all the agent cells
		List<ProbabilityCell> agentProbs = this.getAgentProbs(agent);
		if (agentProbs.size() == 0)
			return null;
		//calc probability
		for (ProbabilityCell probabilityCell : agentProbs) {
			sum+=probabilityCell.getProbability();
			if(randomProb < sum)
				return probabilityCell;
			
		}
		return agentProbs.get(agentProbs.size()-1);
	}



	public List<ProbabilityCell> getAgentProbs(String agent) {
		List<ProbabilityCell> agentProbs = new ArrayList<ProbabilityCell>();
		for (ProbabilityCell probabilityCell : (ProbabilityCell[])this.cells) {
			if(probabilityCell.getAgentName() == agent)
				agentProbs.add(new ProbabilityCell(probabilityCell));
		}
		return agentProbs;
	}
	
	public void UpdateSumOfProbabilities()
	{
		String[] agents = InputsReader.getAgents();
		
		for (String agent : agents) {
			this.agentsTotalProbabilities.put(agent, 1.0);
		}
	}


	//return only cells that are with probability = 1 
	public List<ProbabilityCell> getOneLeftProbCells() {
		List<ProbabilityCell> ans = new ArrayList<ProbabilityCell>();
		for (String agent : this.getAgentsNames()) {
			List<ProbabilityCell> lastCells = this.getAgentProbs(agent);
			if (lastCells.size() == 1)
				ans.add(lastCells.get(0));
		}
		 
		return ans;
	}

}
